<?php

namespace App\Http\Controllers\Wechat;

use App\Http\Controllers\AccessSystem\IndexController;
use App\Http\Controllers\ScoreRuleController;
use App\Models\AppInviteCodeBehavior;
use App\Models\OtherAccessNum;
use App\Models\StudyRoomReservation;
use App\Models\StudyRoomReservationApply;
use App\Models\StudyRoomReservationSchedule;
use App\Models\StudyRoomReservationSpecialSchedule;
use App\Models\UserLibraryInfo;
use App\Models\UserViolate;
use App\Validate\StudyRoomReservationValidate;
use Exception;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 书房预约类
 * Class Reservation
 * @package app\port\controller
 */
class StudyRoomReservationController extends CommonController
{
    protected $model;
    protected $applyModel;
    protected $validate;
    protected $score_type = 16; //积分类型

    public function __construct()
    {
        parent::__construct();

        $this->model = new StudyRoomReservation();
        $this->applyModel = new StudyRoomReservationApply();
        $this->validate = new StudyRoomReservationValidate();
    }


    /**
     * 书房预约列表
     * @param page int 当前页数
     * @param limit int 分页大小
     * @param start_time int 开始时间
     * @param end_time int 结束时间
     * @param keywords string 搜索筛选
     */
    public function lists()
    {
        $page = $this->request->page ? intval($this->request->page) : 1;
        $limit = $this->request->limit ? $this->request->limit : 10;
        $start_time = $this->request->start_time;
        $end_time = $this->request->end_time;
        $keywords = $this->request->keywords;

        $res = $this->model->lists(['id', 'name', 'apply_number', 'img', 'intro'], $keywords, $start_time, $end_time, 1, $limit);


        //添加书房预约访问量（应用）
        $otherAccessNumModel = new OtherAccessNum();
        $otherAccessNumModel->add(5);

        //增加行为分析
        $appInviteCodeBehaviorModel = new AppInviteCodeBehavior();
        $appInviteCodeBehaviorModel->add(5);

        if (empty($res['data'])) {
            return $this->returnApi(203, "暂无数据");
        }

        $res = $this->disPageData($res);

        return $this->returnApi(200, "查询成功", true, $res);
    }

    /**
     * 预约详情
     * @param  $authorrization ：用户 token   可选
     * @param  $id 文化配送id               （主要查看物品详情）
    // * @param  $make_id   预约的id    二者2选一   （主要查看自己预约的详情 ， 如果 传make_id  $authorrization 必须存在）
     */
    public function detail()
    {
        $this->model->checkApplyStatus(); //处理逾期报名信息

        //增加验证场景进行验证
        if (!$this->validate->scene('wx_detail')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }

        $id = $this->request->input('id');
        $user_id = $this->request->user_info['id'];
        if (empty($id)) {
            return $this->returnApi(201, 'id不能为空');
        }

        // $make_id = $this->request->input('make_id');
        // if (!empty($make_id) && empty($user_id)) {
        //     return $this->returnApi(201, '用户信息不能为空');
        // } elseif (empty($make_id) && empty($id)) {
        //     return $this->returnApi(201, '物品id不能为空');
        // }

        //获取预约信息
        // if (!empty($make_id)) {
        //     $make_info = $this->applyModel->getMakeInfo($make_id);
        //     if (empty($make_info)) {
        //         return $this->returnApi(203, '预约信息不能为空');
        //     }
        //     //处理特殊日期和一般日期
        //     $schedule_type = $make_info['schedule_type'];
        //     $make_info['start_time'] = $schedule_type == 1 ? $make_info['normal_start_time'] : $make_info['special_start_time'];
        //     $make_info['end_time'] = $schedule_type == 1 ? $make_info['normal_end_time'] : $make_info['special_end_time'];

        //     $id = $make_info['reservation_id'];
        // }

        $res = $this->model->detail($id);

        if (!$res) {
            return $this->returnApi(201, '参数传递错误');
        }
        $res = $res->toArray();
        $display_day = !empty($res['display_day']) ? $res['display_day'] : 7;
        $res['make_quantum'] = $this->model->getMakeTime($user_id, $res, $display_day); //获取排版
        $res['type_tag'] = !empty($res['type_tag']) ? explode("|", $res['type_tag']) : [];

        //增加返回预约信息
        if (!empty($make_info)) {
            $make_info['make_time'] = date("Y/m/d", strtotime($make_info['make_time']));
            $res['make_info'] = $make_info;
            unset($res['make_info']['reservation_id']);
        } else {
            $res['make_info'] = null; //没有预约信息就返回null
        }

        unset($res['reservation_type']);

        $real_info_arr = $this->model->getReservationApplyParam(); //获取所有的数据
        $res['real_info'] = $this->getRealInfoArray($res['real_info'], $real_info_arr);
        /**
         * 判断是否有足够积分参加活动
         */
        $res['is_can_make'] = true;
        if (config('other.is_need_score') && !empty($account_id) && $res['is_reader'] == 1) {
            $scoreRuleObj = new ScoreRuleController();
            $score_status = $scoreRuleObj->checkScoreStatus($this->score_type, $user_id, $account_id);
            if ($score_status['code'] == 202 || $score_status['code'] == 203) $res['is_can_make'] = '积分不足不能预约';
        }
        //限制预约次数
        if (!empty($res->limit_num)) {
            $res_number = $this->applyModel->getReservationNotOutNumber($user_id, $id);
            if ($res_number >= $res->limit_num) {
                $res['is_can_make'] = '已达到违规次数上限,不能进行此操作';
            }
        }
        /*检查是否违规*/
        $validateModel = new UserViolate();
        $isViolate = $validateModel->checkIsViolate($user_id, 'study_room_reservation');
        if ($isViolate) {
            $res['is_can_make'] = '已达到违规次数上限,不能进行此操作';
        }

        return $this->returnApi(200, '获取成功', true, $res);
    }

    /**
     * 文化配送 预约时间段
     * @param $token    必选
     * @param $id 文化配送id
     * @param $schedule_id 排班id
     * @param $schedule_type 排班类型
     * @param $make_time 需要预约时间
     * @param $number    多物品预约时的数量  多物品必须 其他可不传
     * @param username  姓名
     * @param id_card  身份证
     * @param tel  电话号码
     * @param reader_id  读者证
     * @param img  头像
     * @param remark  备注 可选  除备注外，其余都是必填
     * @param unit 单位
     * @param age  年龄
     * @param sex  性别  1 男  2 女
     *
     */
    public function makeInfo()
    {
        $this->model->checkApplyStatus(); //处理逾期报名信息

        //增加验证场景进行验证
        if (!$this->validate->scene('wx_make')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $user_id = $this->request->user_info['id'];
        $account_id = $this->request->user_info['account_id'];
        $id = $this->request->input('id', '');
        $this->request->merge(['make_time' => date('Y-m-d', strtotime($this->request->make_time))]);

        //限制用户多次点击
        $key = md5('study_room_reservation_apply' . $user_id . $id . request()->ip());
        $oldKey = Cache::get($key); //没有缓存返回false
        if ($oldKey) {
            return $this->returnApi(201, "您操作的太频繁了，请稍后重试");
        } else {
            Cache::put($key, 1, 3);
        }

        /*检查是否违规*/
        $validateModel = new UserViolate();
        $isViolate = $validateModel->checkIsViolate($user_id, 'study_room_reservation');
        if ($isViolate) {
            return $this->returnApi(201, '已达到违规次数上限,不能进行此操作');
        }

        //判断当前预约是否有，特殊排版
        $reservationSpecialScheduleModel = new StudyRoomReservationSpecialSchedule();
        $special_info = $reservationSpecialScheduleModel->getSpecialListByDate($id, $this->request->make_time);
        if ($special_info && $this->request->schedule_type == 1) {
            return $this->returnApi(201, "网络异常，请稍后重试");
        }

        $res_info = $this->model->where('id', $id)->where('is_del', 1)->where('is_play', 1)->first();
        if (empty($res_info)) {
            return $this->returnApi(202, '预约不存在');
        }

        //判断是否有不能预约的时间段
        if ($res_info['day_make_time']) {
            if (date('H:i:s') < $res_info['day_make_time']) {
                return $this->returnApi(202, '预约还未开始，请稍后再来');
            }
        }
        //判断只能预约几天的数据
        $display_day = !empty($res_info['display_day']) ? $res_info['display_day'] : 7;
        $now_time = date('Y-m-d', strtotime("+$display_day day"));
        //不能超过设置的预约天数
        if ($now_time <=  $this->request->make_time || $this->request->make_time < date('Y-m-d')) {
            return $this->returnApi(202, "预约时间段有误，请重新检查");
        }
        //取消预约后10分钟之内不能在预约当前预约（到馆预约是不能预约当前座位）
        $selfCancelMakeInfo = $this->applyModel->selfMakeStatus($user_id, $id, $this->request->schedule_id, $this->request->schedule_type, $this->request->make_time, [2]);
        if ($selfCancelMakeInfo && $selfCancelMakeInfo['change_time'] > date('Y-m-d H:i:s', strtotime("-10 min"))) {
            return $this->returnApi(202, '取消预约后10分钟之内不能再次预约');
        }

        //限制预约次数
        if (!empty($res_info->limit_num)) {
            $res_number = $this->applyModel->getReservationNotOutNumber($user_id, $id);
            if ($res_number >= $res_info->limit_num) {
                return $this->returnApi(202, '您当前预约次数已达到上限');
            }
        }

        //判断是否需要绑定读者证
        if (config('other.is_validate_lib_api')) {
            if ($res_info->is_reader == 1) {
                //判断读者证号密码是否正确 和是否绑定读者证
                $userLibraryInfoModel = new UserLibraryInfo();
                $account_lib_info = $userLibraryInfoModel->checkAccountPwdIsNormal($user_id);
                if (is_string($account_lib_info)) {
                    return $this->returnApi(204, $account_lib_info);
                }
                $account_id = $account_lib_info['id'];
            }
            if ($res_info['is_reader'] == 1 && empty($account_id)) {
                return $this->returnApi(201, '请先绑定读者证');
            }
        }

        //判断积分是否满足要求
        if (config('other.is_need_score') && $res_info->is_reader == 1) {
            $scoreRuleObj = new ScoreRuleController();
            $score_status = $scoreRuleObj->checkScoreStatus($this->score_type, $user_id, $account_id);
            if ($score_status['code'] == 202 || $score_status['code'] == 203) return $this->returnApi(202, $score_status['msg']);
        }

        $scheduleModel = $this->request->schedule_type == 2 ? new StudyRoomReservationSpecialSchedule() : new StudyRoomReservationSchedule();
        $schedule_info = $scheduleModel->where('id', $this->request->schedule_id)->first();
        //判断当前时间段  是否不能预约
        if (date('Y-m-d') == $this->request->make_time && date('H:i:s', strtotime("+30 min")) > $schedule_info['end_time']) {
            return $this->returnApi(202, '预约失败，当前时间段不允许预约');
        }
        if ($this->request->number > 1) {
            return $this->returnApi(202, '预约数量不正确');
        }

        DB::beginTransaction();
        try {
            $res_info = $this->model->where('id', $id)->where('is_del', 1)->where('is_play', 1)->lockForUpdate()->first();
            if (empty($res_info)) {
                throw new Exception('预约不存在');
            }
            //判断自己是否已预约
            $selfStatus = $this->applyModel->selfMakeStatus($user_id, $id, $this->request->schedule_id, $this->request->schedule_type, $this->request->make_time);
            if ($selfStatus) {
                throw new Exception('您已预约，请勿重复预约');
            }
            //判断此时间段是否已预约完毕
            $status = $this->applyModel->makeStatus($id, $this->request->schedule_id, $this->request->schedule_type, $this->request->make_time, $res_info->number);
            if ($status !== false && $status <= 0) {
                throw new Exception('当前时间段预约已满，请重新选择');
            }
            $where = [];
            if ($res_info->is_real == 1) {
                if (!empty($res_info->real_info)) {
                    $real_info = explode('|', $res_info->real_info);
                    $where = $this->model->checkApplyParam($res_info, $real_info, $this->request->all());
                }
            }
            //获取预约结束时间
            if ((date('Y/m/d') == $this->request->make_time || date('Y-m-d') == $this->request->make_time) && date('H:i:s') > $schedule_info['start_time']) {
                $where['expire_time'] = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s') . "+" . $res_info['clock_time'] . " min"));
            } else {
                $where['expire_time'] = date('Y-m-d H:i:s', strtotime($this->request->make_time . ' ' . $schedule_info['start_time'] . " +" . $res_info['clock_time'] . " min"));
            }

            //检查是否需要审核
            $where['status'] = $res_info['is_approval'] == 1 ? 3 : 1;

            $where['schedule_id'] = $this->request->schedule_id;
            $where['schedule_type'] = $this->request->schedule_type;
            $where['number'] = $this->request->number ? $this->request->number : 1;
            $where['account_id'] = !empty($account_id) ? $account_id : 0;
            $where['user_id'] = !empty($user_id) ? $user_id : 0; //微信报名增加
            $where['score'] = !empty($score_status['score_info']['score']) ? $score_status['score_info']['score'] : 0;
            $where['reservation_id'] = $id;
            $where['make_time'] = $this->request->make_time;
            $this->applyModel->add($where);

            $number = $this->request->number ? $this->request->number : 1;
            $res_info->apply_number = $res_info->apply_number + $number;
            $res_info->save(); //添加预约数量

            $msg = $res_info->is_approval == 1 ? "提交" : '申请';
            $system_id = $this->systemAdd('空间预约申请', $user_id, $account_id, 54, intval($this->applyModel->id), '您的预约申请：【' . $res_info->name . '】' . $msg . '成功！');

            /**执行积分规则 */
            if (!empty($score_status['code']) && $score_status['code'] == 200) {
                $scoreRuleObj->scoreChange($score_status, $user_id, $account_id, $system_id); //添加积分消息
            }
            DB::commit();
            return $this->returnApi(200, '预约成功', true);
        } catch (\Exception $e) {
            DB::rollBack();
            //   return $this->returnApi(202, $e->getMessage() . $e->getFile() . $e->getLine());
            // $msg = $e->getCode() == 2002 ? $e->getMessage() : '预约失败';
            return $this->returnApi(202, $e->getMessage());
        }
    }


    /**
     * 用户取消预约  （is_cancel 是否可以取消，如果不可以取消，则任何状态都不能取消，如果是可以取消，
     *                  则还需要根据 is_approval 是否需要审核字段判断，如果需要审核，则在审核期间可以取消，其他不可取消，
     *                  如果不需要审核，则在已通过可以取消，其他不能取消）
     * @param  $token   必选
     * @param  $make_id  预约id
     */
    public function cancelMake()
    {
        $this->model->checkApplyStatus(); //处理逾期报名信息
        $user_id = $this->request->user_info['id'];
        $account_id = $this->request->user_info['account_id'];
        //增加验证场景进行验证
        if (!$this->validate->scene('wx_cancel_make')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $make_info = $this->applyModel->where('id', $this->request->make_id)->first();
        if (!$make_info) {
            return $this->returnApi(201, '参数传递错误');
        }
        if ($make_info->user_id != $user_id) {
            return $this->returnApi(202, '您无权取消此预约');
        }
        //限制用户多次点击
        $key = md5('study_room_reservation_apply' . $user_id . $make_info['reservation_id'] . request()->ip());
        $oldKey = Cache::get($key); //没有缓存返回false
        if ($oldKey) {
            return $this->returnApi(201, "您操作的太频繁了，请稍后重试");
        } else {
            Cache::put($key, 1, 3);
        }

        $reservation_info = $this->model->where('id', $make_info['reservation_id'])->first();

        $is_can_cancel = $this->applyModel->isCanCancel($reservation_info, $make_info);
        if ($is_can_cancel !== true) {
            return $this->returnApi(202, $is_can_cancel);
        }
        DB::beginTransaction();
        try {
            $make_info->status = 2;
            $make_info->change_time = date("Y-m-d H:i:s");
            $make_info->save();

            $this->model->where('id', $make_info->reservation_id)->decrement('apply_number'); //减少预约数量

            /*消息推送*/
            $system_id = $this->systemAdd('取消预约', $user_id, $account_id, 55, $this->request->make_id, '您的预约：【' . $reservation_info->name . '】已取消成功');

            /**执行积分规则 */
            if (!empty($make_info->score)) {
                $scoreRuleObj = new ScoreRuleController();
                $score_msg = $scoreRuleObj->getScoreMsg($make_info->score);
                $scoreRuleObj->scoreReturn($this->score_type, $make_info->score, $make_info->user_id, $make_info->account_id, '取消空间预约，' . $score_msg . ' ' . abs($make_info->score) . ' 积分', $system_id, '取消空间预约');
            }

            DB::commit();
            return $this->returnApi(200, '取消预约成功', true);
        } catch (\Exception $e) {
            $msg = $e->getCode() == 2002 ? $e->getMessage() : "取消预约失败";
            DB::rollBack();
            return $this->returnApi(202, $msg);
        }
    }


    /**
     * 我的预约列表
     * @param  $authorrization ：用户 token   必选
     * @param  $status  预约状态   1.已通过（待使用）  2.已取消，3 待审核（待审核）  4已拒绝 ,5 已过期 , 6 已签到（已使用）  7 结束打卡（增对座位预约）（已使用）
     *                  状态可分为 3类  全部  待审核3   待使用1  已使用 67  其余展示在全部里面
     * @param  $page  页数  默认为 1
     * @param  $limit  分页限制  默认为 10
     */
    public function myMakeList()
    {
        $this->model->checkApplyStatus(); //处理逾期报名信息

        $status = $this->request->input('status') ?: 0;
        $page = $this->request->input('page', 1) ?: 1;
        $limit = $this->request->input('limit', 10) ?: 10;
        $user_id = $this->request->user_info['id'];

        $data = $this->applyModel->myMakeList($user_id, $status, $limit);
        if ($data['data']) {
            $data = $this->disPageData($data);
            return $this->returnApi(200, '获取成功', true, $data);
        }
        return $this->returnApi(203, '暂无数据');
    }

    /**
     * 出示二维码
     * @param  $authorrization ：用户 token   必选
     * @param apply_id int 预约id  
     */
    public function getApplyQr()
    {
        $user_id = $this->request->user_info['id'];
        $apply_id = $this->request->apply_id;

        $is_can_show_qr = $this->applyModel->isCanShowQr($user_id, $apply_id);
        if ($is_can_show_qr !== true) {
            return $this->returnApi(202, $is_can_show_qr);
        }
        //可以出示二维码
        $accessSystemObj = new IndexController();
        $user_id = sprintf("%08d", $user_id);
        $qr_url = $accessSystemObj->createQr($user_id, 'AIl_Viewld', 2);
        if ($qr_url) {
            return $this->returnApi(200, "二维码生成成功", true, ['qr_url' => $qr_url]);
        }
        return $this->returnApi(202, '二维码生成失败，请重试！');
    }


    /**
     * 出示二维码(第一版本)
     * @param  $authorrization ：用户 token   必选
     * @param reservation_id int 预约id  
     */
    public function _getApplyQr()
    {
        $user_id = $this->request->user_info['id'];
        $reservation_id = $this->request->reservation_id;

        $week = date("w");
        $weeks = $week ? $week : 7;
        //查看指定日期是否有特殊时间设置
        $studyRoomReservationScheduleModel = new StudyRoomReservationSchedule();
        list($schedule_type, $reservation_schedule) = $studyRoomReservationScheduleModel->getReservationSchedule($reservation_id, $weeks);
        if ($schedule_type === false) {
            return $this->returnApi(202, $reservation_schedule);
        }

        $studyRoomReservationApplyModel = new StudyRoomReservationApply();
        $now_make_info = $studyRoomReservationApplyModel->nowTimeMakeInfo($user_id, $reservation_id, $reservation_schedule['id'], $schedule_type, null, [1, 6]);
        if ($now_make_info) {
            //可以出示二维码
            $accessSystemObj = new IndexController();
            $user_id = sprintf("%08d", $user_id);
            $qr_url = $accessSystemObj->createQr($user_id, 'AIl_Viewld', 2);
            if ($qr_url) {
                return $this->returnApi(200, "二维码生成成功", true, ['qr_url' => $qr_url]);
            }
            return $this->returnApi(202, '二维码生成失败，请重试！');
        }
        return $this->returnApi(203, '当前时间段无预约信息');
    }
}
